#include <utf.h>
#include <s32strm.h>
#include <s32mem.h>

#include "BSON.h"

namespace
{

TInt ComputeUtf8StringLength(const TDesC& aString)
{
  TInt totalLength = 0;
  for ( TInt i = 0; i < aString.Length(); ++i )
  {
    TUint16 c = aString[i];
    if ( c <= 0x007F )
      totalLength += 1;
    else if ( c <= 0x07FF )
      totalLength += 2;
    else// if ( c <= 0xFFFF )//TUint16 value is alvays <= 0xFFFF
      totalLength += 3;
//    else if ( c <= 0x10FFFF )
//      totalLength += 4;
  }
  return totalLength + 1;//for terminating \0x00 symbol  
}

TInt ComputeCStringDataLength(const TDesC& aString)
{
  return ComputeUtf8StringLength(aString);
}

TInt ComputeStringDataLength(const TDesC& aString)
{
  return 4 + ComputeUtf8StringLength(aString);//4 is for leading 32byte length.
}

HBufC* ReadNameL(RReadStream& aIn)
{
  RBuf8 tmpUtf8name;
  tmpUtf8name.CreateL(64);
  CleanupClosePushL(tmpUtf8name);
  TUint8 byte = aIn.ReadUint8L();
  while (byte)
  {
    if ( tmpUtf8name.Length() == tmpUtf8name.MaxLength() )
      tmpUtf8name.ReAllocL(tmpUtf8name.MaxLength()*2);

    tmpUtf8name.Append(TChar(byte));
    byte = aIn.ReadUint8L();
  }
  HBufC* unicodeName = CnvUtfConverter::ConvertToUnicodeFromUtf8L(tmpUtf8name);
  CleanupStack::PopAndDestroy(&tmpUtf8name);
  return unicodeName;
}

void SerializeL(::RWriteStream &aOut, const TDesC& aString)
{
  HBufC8* utfConvertedName = CnvUtfConverter::ConvertFromUnicodeToUtf8L(aString);
  CleanupStack::PushL(utfConvertedName);
  ASSERT(utfConvertedName->Length() == ComputeUtf8StringLength(aString) - 1);

  aOut.WriteInt32L(utfConvertedName->Length()+1);
  aOut.WriteL(*utfConvertedName);
  aOut.WriteInt8L(0);

  CleanupStack::PopAndDestroy(utfConvertedName);
}

void DeserializeL(::RReadStream &aIn, RBuf& aString)
{
  TInt length = aIn.ReadInt32L();
  RBuf8 utf8Buff;
  utf8Buff.CreateL(length);
  CleanupClosePushL(utf8Buff);

  aIn.ReadL(utf8Buff);

  if ( aIn.ReadUint8L() != 0 )
    User::Leave(KErrCorrupt);

  HBufC* unicodeValue = CnvUtfConverter::ConvertToUnicodeFromUtf8L(utf8Buff);
  aString.Close();
  aString.Assign(unicodeValue);

  CleanupStack::PopAndDestroy(&utf8Buff);
}

//writes string in cstring format
void SerializeInCStringFormatL(::RWriteStream &aOut, const TDesC& aString)
{
  HBufC8* utfConvertedName = CnvUtfConverter::ConvertFromUnicodeToUtf8L(aString);
  CleanupStack::PushL(utfConvertedName);

  aOut.WriteL(*utfConvertedName);
  aOut.WriteInt8L(0);

  CleanupStack::PopAndDestroy(utfConvertedName);
}

using namespace BSON;
CElement* DeserializeElementLC(RReadStream& aIn, HBufC*& aName)
{
  TElementType type = static_cast<TElementType>(aIn.ReadUint8L());
  HBufC* name = ReadNameL(aIn);
  CleanupStack::PushL(name);

  CElement* element = NULL;
  switch (type)
  {
    case EDouble:
      element = CDouble::NewL(aIn);
      break;
    case EUtf8String:
    case EJavaScriptCode:
    case ESymbol:
      element = CString::NewL(aIn, type);
      break;
    case EDocument:
      element = CDocument::NewL(aIn);
      break;
    case EArray:
      element = CArray::NewL(aIn);
      break;
    case BSON::EBinary:
      element = CBinary::NewL(aIn);
      break;
    case EBoolean:
      element = CBoolean::NewL(aIn);
      break;
    case EUtcDateTime:
      element = CUtcDateTime::NewL(aIn);
      break;
    case ENull:
      element = CNull::NewL(aIn);
      break;
    case EInt32:
      element = CInt32::NewL(aIn);
      break;
    case EInt64:
      element = CInt64::NewL(aIn);
      break;
    default:
      User::Leave(KErrCorrupt);
  }
  CleanupStack::Pop(name);
  CleanupStack::PushL(element);
  aName = name;
  return element;
}

}

namespace BSON
{

TInt CElement::TypeSignatureLength()
{
  return 1;
}

//HBufC8* CElement::SerializeL() const
//{
//  TInt outputLength = TypeSignatureLength() + DataLength();
//
//  HBufC8* output = HBufC8::NewLC(outputLength);
//  TPtr8 p = output->Des();
//  RDesWriteStream outStream(p);
//  CleanupClosePushL(outStream);
//
//  SerializeL(outStream);
//
//  CleanupStack::Pop(&outStream);
//  CleanupStack::Pop(output);
//
//  return output;
//}

//void CElement::SerializeL(::RWriteStream &aOut) const
//{
//  aOut.WriteInt8L(static_cast<TInt>(Type()));
//  DoSerializeL(aOut);
//}




CNull::CNull()
{}

CNull* CNull::NewL()
{
  return new (ELeave) CNull();
}

CNull* CNull::NewL(RReadStream&/*aIn*/)
{
  return new (ELeave) CNull();
}

TElementType CNull::Type() const
{
  return ENull;
}

TInt CNull::DataLength() const
{
  return 0;
}

void CNull::DoSerializeL(RWriteStream &/*aOut*/) const
{}

void CNull::DoDeserializeL(RReadStream &/*aIn*/)
{}


namespace _
{

void SerializeL(RWriteStream &aOut, const TReal64& aVal)
{
  aOut.WriteL(TPckgC<TReal64>(aVal));
}

void SerializeL(RWriteStream &aOut, const bool& aVal)
{
  aOut.WriteL(TPckgC<TUint8>(aVal));
}

void SerializeL(RWriteStream &aOut, const TTime& aVal)
{
  aOut.WriteL(TPckgC<TInt64>(aVal.Int64()));
}

void SerializeL(RWriteStream &aOut, const TInt32& aVal)
{
  aOut.WriteL(TPckgC<TInt32>(aVal));
}

void SerializeL(RWriteStream &aOut, const TInt64& aVal)
{
  aOut.WriteL(TPckgC<TInt64>(aVal));
}



void DeserializeL(RReadStream &aIn, TReal64& aVal)
{
  TPckg<TReal64> pckg(aVal);
  aIn.ReadL(pckg);
}

void DeserializeL(RReadStream &aIn, bool& aVal)
{
  TPckg<TUint8> pckg(aVal);
  aIn.ReadL(pckg);
}

void DeserializeL(RReadStream &aIn, TTime& aVal)
{
  TInt64 timeval = 0;
  TPckg<TInt64> pckg(timeval);
  aIn.ReadL(pckg);
  aVal = TTime(timeval);
}

void DeserializeL(RReadStream &aIn, TInt32& aVal)
{
  TPckg<TInt32> pckg(aVal);
  aIn.ReadL(pckg);
}

void DeserializeL(RReadStream &aIn, TInt64& aVal)
{
  TPckg<TInt64> pckg(aVal);
  aIn.ReadL(pckg);
}


}//namespace _


CElement::~CElement()
{}



template class CValue<EDouble>;
template class CValue<EBoolean>;
template class CValue<EUtcDateTime>;
template class CValue<EInt32>;
template class CValue<EInt64>;




CString::CString(TElementType aType)
  : iType(aType)
{}

CString::~CString()
{
  iValue.Close();
}

CString* CString::NewLC(HBufC* aValue, TElementType aType)
{
  if ( !aValue || (aType != EUtf8String && aType != EJavaScriptCode && aType != ESymbol) )
    User::Leave(KErrArgument);

  CString* This = new (ELeave) CString(aType);
  CleanupStack::PushL(This);
  
  This->iValue.Assign(aValue);
  return This;
}

CString* CString::NewL(HBufC* aValue, TElementType aType)
{
  CString* This = NewLC(aValue, aType);
  CleanupStack::Pop(This);
  return This;
}

CString* CString::NewLC(const TDesC& aValue, TElementType aType)
{
  if ( aType != EUtf8String && aType != EJavaScriptCode && aType != ESymbol )
    User::Leave(KErrArgument);

  CString* This = new (ELeave) CString(aType);
  CleanupStack::PushL(This);
  
  This->iValue.Create(aValue);
  return This;
}

CString* CString::NewL(const TDesC& aValue, TElementType aType)
{
  CString* This = NewLC(aValue, aType);
  CleanupStack::Pop(This);
  return This;
}

CString* CString::NewL(RReadStream& aIn, TElementType aType)
{
  if ( aType != EUtf8String && aType != EJavaScriptCode && aType != ESymbol )
    User::Leave(KErrArgument);

  CString* string = new (ELeave) CString(aType);
  CleanupStack::PushL(string);
  string->DoDeserializeL(aIn);
  CleanupStack::Pop(string);
  return string;
}

TPtrC CString::Value() const
{
  return iValue;
}

void CString::SetValueL(const TDesC& aNewValue)
{
  if ( iValue.MaxLength() < aNewValue.Length() )
    iValue.Copy(aNewValue);
  else
  {
    iValue.Close();
    iValue.Create(aNewValue);
  }
}

void CString::SetValue(HBufC* aNewValue)
{
  iValue.Close();
  iValue.Assign(aNewValue);
}

TElementType CString::Type() const
{
  return iType;
}

void CString::DoSerializeL(RWriteStream &aOut) const
{
  ::SerializeL(aOut, iValue);
}

void CString::DoDeserializeL(RReadStream &aIn)
{
  DeserializeL(aIn, iValue);
}

//Compute the length of the data in utf8 format
TInt CString::DataLength() const
{
  return ComputeStringDataLength(iValue);
}

namespace
{

TBool IsValidBinarySubTypeValue(CBinary::TSubType aSubType)
{
  if (   aSubType == CBinary::EGeneric
      || aSubType == CBinary::EFunction
      || aSubType == CBinary::EOldBinary
      || aSubType == CBinary::EUUID
      || aSubType == CBinary::EMD5
      || aSubType == CBinary::EUserDefined )
  {
    return ETrue;
  }
  else
    return EFalse;
}

}


CBinary::CBinary(TSubType aSubType)
  : iSubType(aSubType)
{}

CBinary* CBinary::NewL(const TDesC8& aData, TSubType aSubType)
{
  if ( !IsValidBinarySubTypeValue(aSubType) )
    User::Leave(KErrArgument);

  CBinary* This = new (ELeave) CBinary(aSubType);
  CleanupStack::PushL(This);
  This->iValue.Assign(aData.AllocL());
  CleanupStack::Pop(This);
  return This;
}

CBinary* CBinary::NewL(HBufC8* aData, TSubType aSubType)
{
  if ( !aData || !IsValidBinarySubTypeValue(aSubType) )
    User::Leave(KErrArgument);

  CBinary* This = new (ELeave) CBinary(aSubType);
  CleanupStack::PushL(This);
  This->iValue.Assign(aData);
  CleanupStack::Pop(This);
  return This;
}

CBinary* CBinary::NewL(RReadStream& aIn)
{
  CBinary* binary = NewL(NULL, EGeneric);
  CleanupStack::PushL(binary);
  binary->DoDeserializeL(aIn);
  CleanupStack::Pop(binary);
  return binary;
}

CBinary::~CBinary()
{
  iValue.Close();
}

TPtrC8 CBinary::Value() const
{
  return iValue;
}

void CBinary::SetValueL(const TDesC8& aData)
{
  if ( iValue.MaxLength() >= aData.Length() )
    iValue.Copy(aData);
  else
  {
    iValue.Close();
    iValue.CreateL(aData);
  }
}

void CBinary::SetValue(HBufC8* aData)
{
  iValue.Close();
  iValue.Assign(aData);
}

CBinary::TSubType CBinary::SubType() const
{
  return iSubType;
}

TElementType CBinary::Type() const
{
  return EBinary;
}

void CBinary::DoSerializeL(RWriteStream &aOut) const
{
  aOut.WriteInt32L(iValue.Length());
  aOut.WriteUint8L(iSubType);
  aOut.WriteL(iValue);
}

void CBinary::DoDeserializeL(RReadStream &aIn)
{
  TInt length = aIn.ReadInt32L();

  TSubType newSubType = static_cast<TSubType>(aIn.ReadUint8L());
  RBuf8 newValue;
  newValue.CreateL(length);
  CleanupClosePushL(newValue);
  aIn.ReadL(newValue);

  iValue.Swap(newValue);
  CleanupStack::PopAndDestroy(&newValue);

  iSubType = newSubType;
}

TInt CBinary::DataLength() const
{
  return iValue.Length() + 1;//+1 is for subtype
}


CArray* CArray::NewLC()
{
  CArray* This = new (ELeave) CArray();
  CleanupStack::PushL(This);
  This->ConstructL();
  return This;
}

CArray* CArray::NewL()
{
  CArray* This = NewLC();
  CleanupStack::Pop(This);
  return This;
}

CArray* CArray::NewL(RReadStream& aIn)
{
  CArray* array = NewLC();
  array->DoDeserializeL(aIn);
  CleanupStack::Pop(array);
  return array;
}

CArray::~CArray()
{
  iElements.ResetAndDestroy();
  iNameGenerator.Close();
}

CArray::CArray()
{}

void CArray::ConstructL()
{
  iNameGenerator.CreateMaxL(10);
}

void CArray::Reset()
{
  iElements.ResetAndDestroy();
}

TInt CArray::Count() const
{
  return iElements.Count();
}

CElement& CArray::operator[](TInt aIndex)
{
  return *iElements[aIndex];
}

const CElement& CArray::operator[](TInt aIndex) const
{
  return *iElements[aIndex];
}

void CArray::AppendL(CElement* aValue)
{
  if ( !aValue )
    User::Leave(KErrArgument);

  iElements.AppendL(aValue);
}

void CArray::AppendL()
{
  SafeAppendL(CNull::NewL());
}
void CArray::AppendL(bool aValue)
{
  SafeAppendL(CBoolean::NewL(aValue));
}

void CArray::AppendL(TInt aValue)
{
  if ( sizeof(aValue) <= sizeof(TInt32) )
    AppendL(static_cast<TInt32>(aValue));
  else
    AppendL(static_cast<TInt64>(aValue));
}

void CArray::AppendL(TInt32 aValue)
{
  SafeAppendL(CInt32::NewL(aValue));
}

void CArray::AppendL(const TInt64& aValue)
{
  SafeAppendL(CInt64::NewL(aValue));
}

void CArray::AppendL(const TTime& aValue)
{
  SafeAppendL(CUtcDateTime::NewL(aValue));
}

void CArray::AppendL(const TReal64& aValue)
{
  SafeAppendL(CDouble::NewL(aValue));
}

void CArray::AppendL(const TDesC& aString, TElementType aType)
{
  SafeAppendL(CString::NewL(aString, aType));
}

void CArray::AppendL(HBufC* aString, TElementType aType)
{
  SafeAppendL(CString::NewL(aString, aType));
}

void CArray::AppendL(const TDesC8& aBinary, CBinary::TSubType aSubType)
{
  SafeAppendL(CBinary::NewL(aBinary, aSubType));
}

void CArray::AppendL(HBufC8* aBinary, CBinary::TSubType aSubType)
{
  SafeAppendL(CBinary::NewL(aBinary, aSubType));
}

TElementType CArray::Type() const
{
  return EArray;
}

TInt CArray::DataLength() const
{
  TInt length = 4;// +4 is for leading 32byte length of the document
  for ( TInt i = 0; i < iElements.Count(); ++i )
  {
    length += TypeSignatureLength();
    length += ComputeIndexNameLength(i);
    length += iElements[i]->DataLength();
  }
  length += 1;// +1 is for terminating \0x00 symbol
  return length;
}

void CArray::DoSerializeL(::RWriteStream &aOut) const
{
  TInt length = CArray::DataLength();
  aOut.WriteInt32L(length);
  for ( TInt i = 0; i < iElements.Count(); ++i )
  {
    const CElement& element = *iElements[i];
    aOut.WriteInt8L(element.Type());
    SerializeInCStringFormatL(aOut, NameForIndex(i));
    element.DoSerializeL(aOut);
  }
  aOut.WriteInt8L(0);
}

void CArray::DoDeserializeL(RReadStream &aIn)
{
  TInt32 docLength = aIn.ReadInt32L();

  TStreamPos pos = aIn.Source()->TellL(MStreamBuf::ERead);
  while ( docLength - pos.Offset() > 1 )
  {
    HBufC* name = NULL;
    CElement* element = ::DeserializeElementLC(aIn, name);
    delete name;
    name = NULL;

    AppendL(element);
    CleanupStack::Pop(element);

    pos = aIn.Source()->TellL(MStreamBuf::ERead);
  }

  TUint8 terminator = aIn.ReadUint8L();
  ASSERT(terminator == 0);
}

void CArray::SafeAppendL(CElement* aElement)
{
  CleanupStack::PushL(aElement);
  AppendL(aElement);
  CleanupStack::Pop(aElement);
}

TInt CArray::ComputeIndexNameLength(TInt aIndex) const
{
  TInt length = 1;
  while(aIndex /= 10)
    ++length;

  return length + 1;//+1 is for \x00 terminator 
}

TPtrC CArray::NameForIndex(TInt aIndex) const
{
  iNameGenerator.Zero();
  iNameGenerator.AppendNum(aIndex);
  return iNameGenerator;
}


CDocument::CValuePair* CDocument::CValuePair::NewL(const TDesC& aName, CElement* aElement)
{
  CValuePair* This = new (ELeave) CValuePair;
  CleanupStack::PushL(This);
  This->iName.CreateL(aName);
  This->iElement = aElement;
  CleanupStack::Pop(This);
  return This;
}

CDocument::CValuePair* CDocument::CValuePair::NewL(HBufC* aName, CElement* aElement)
{
  CValuePair* This = new (ELeave) CValuePair;
  This->iName.Assign(aName);
  This->iElement = aElement;
  return This;
}

CDocument::CValuePair::~CValuePair()
{
  iName.Close();
  delete iElement;
  iElement = NULL;
}

TPtrC CDocument::CValuePair::Name() const
{
  return iName;
}

void CDocument::CValuePair::SetNameL(const TDesC& aName)
{
  RBuf newName;
  newName.CreateL(aName);
  iName.Swap(newName);
  newName.Close();
}

CElement& CDocument::CValuePair::Element()
{
  return *iElement;
}

const CElement& CDocument::CValuePair::Element() const
{
  return *iElement;
}


CDocument* CDocument::NewLC()
{
  CDocument* This = new (ELeave) CDocument;
  CleanupStack::PushL(This);
  return This;
}

CDocument* CDocument::NewL()
{
  CDocument* This = NewLC();
  CleanupStack::Pop(This);
  return This;
}

CDocument* CDocument::NewL(RReadStream& aIn)
{
  CDocument* document = NewLC();
  document->DoDeserializeL(aIn);
  CleanupStack::Pop(document);
  return document;
}

CDocument::~CDocument()
{
  iData.ResetAndDestroy();
}

CDocument::CDocument()
{}

void CDocument::Reset()
{
  iData.ResetAndDestroy();
}

TInt CDocument::Count() const
{
  return iData.Count();
}

CDocument::CValuePair& CDocument::operator[](TInt aIndex)
{
  return *iData[aIndex];
}

const CDocument::CValuePair& CDocument::operator[](TInt aIndex) const
{
  return *iData[aIndex];
}

CElement* CDocument::GetByName(const TDesC& aName)
{
  return const_cast<CElement*>(const_cast<const CDocument*>(this)->GetByName(aName));
}

const CElement* CDocument::GetByName(const TDesC& aName) const
{
  for ( TInt i = 0; i < iData.Count(); ++i )
  {
    if ( iData[i]->Name() == aName )
      return &iData[i]->Element();
  }
  return NULL;
}


void CDocument::AppendL(const TDesC& aName, CElement* aValue)
{
  if ( !aValue )
    User::Leave(KErrArgument);

  CValuePair* newPair = CValuePair::NewL(aName, NULL);
  CleanupStack::PushL(newPair);
  iData.AppendL(newPair);
  CleanupStack::Pop(newPair);
  newPair->iElement = aValue;
}

void CDocument::AppendL(const TDesC& aName)
{
  SafeAppendL(aName, CNull::NewL());
}

void CDocument::AppendL(const TDesC& aName, bool aValue)
{
  SafeAppendL(aName, CBoolean::NewL(aValue));
}
void CDocument::AppendL(const TDesC& aName, TInt aValue)
{
  if ( sizeof(aValue) >= sizeof(TInt32) )
    AppendL(aName, static_cast<TInt32>(aValue));
  else
    AppendL(aName, static_cast<TInt64>(aValue));
}
void CDocument::AppendL(const TDesC& aName, TInt32 aValue)
{
  SafeAppendL(aName, CInt32::NewL(aValue));
}

void CDocument::AppendL(const TDesC& aName, const TInt64& aValue)
{
  SafeAppendL(aName, CInt64::NewL(aValue));
}

void CDocument::AppendL(const TDesC& aName, const TTime& aValue)
{
  SafeAppendL(aName, CUtcDateTime::NewL(aValue));
}

void CDocument::AppendL(const TDesC& aName, const TReal64& aValue)
{
  SafeAppendL(aName, CDouble::NewL(aValue));
}

void CDocument::AppendL(const TDesC& aName, const TDesC& aString, TElementType aType)
{
  SafeAppendL(aName, CString::NewL(aString, aType));
}

void CDocument::AppendL(const TDesC& aName, HBufC* aString, TElementType aType)
{
  SafeAppendL(aName, CString::NewL(aString, aType));
}

void CDocument::AppendL(const TDesC& aName, const TDesC8& aBinary, CBinary::TSubType aSubType)
{
  SafeAppendL(aName, CBinary::NewL(aBinary, aSubType));
}

void CDocument::AppendL(const TDesC& aName, HBufC8* aBinary, CBinary::TSubType aSubType)
{
  SafeAppendL(aName, CBinary::NewL(aBinary, aSubType));
}

void CDocument::SafeAppendL(const TDesC& aName, CElement* aElement)
{
  CleanupStack::PushL(aElement);
  AppendL(aName, aElement);
  CleanupStack::Pop(aElement);
}

void CDocument::AppendL(HBufC* aName, CElement* aElement)
{
  if ( !aElement )
    User::Leave(KErrArgument);

  CValuePair* newPair = CValuePair::NewL(NULL, NULL);

  CleanupStack::PushL(newPair);
  iData.AppendL(newPair);
  CleanupStack::Pop(newPair);

  newPair->iName.Assign(aName);
  newPair->iElement = aElement;
}

TBool CDocument::IsEmbeded() const
{
  return iIsEmbeded;
}
void  CDocument::SetEmbeded(TBool aEmbededVal)
{
  iIsEmbeded = aEmbededVal;
}
HBufC8* CDocument::SerializeLC() const
{
  TInt outputLength = TypeSignatureLength() + DataLength();

  HBufC8* output = HBufC8::NewLC(outputLength);
  TPtr8 p = output->Des();
  RDesWriteStream outStream(p);
  CleanupClosePushL(outStream);

  SerializeL(outStream);

  CleanupStack::PopAndDestroy(&outStream);

  return output;
}

HBufC8* CDocument::SerializeL() const
{
  HBufC8* output = SerializeLC();
  CleanupStack::Pop(output);
  return output;
}

void CDocument::SerializeL(RWriteStream &aOut) const
{
  DoSerializeL(aOut);
}

TElementType CDocument::Type() const
{
  return EDocument;
}

TInt CDocument::DataLength() const
{
  TInt dataLength = 4;//+4 is for leading 32byte length of the document
  for ( TInt i = 0; i < iData.Count(); ++i )
  {
    const CValuePair& pair = *iData[i];
    dataLength += TypeSignatureLength();
    dataLength += ComputeCStringDataLength(pair.Name());
    dataLength += pair.Element().DataLength();
  }
  return dataLength + 1;//+1 is for terminating \0x00 symbol
}

void CDocument::DoSerializeL(::RWriteStream &aOut) const
{
  TInt dataLength = DataLength();
  aOut.WriteInt32L(dataLength);
  for ( TInt i = 0; i < iData.Count(); ++i )
  {
    const CValuePair& pair = *iData[i];
    aOut.WriteUint8L(pair.Element().Type());
    SerializeInCStringFormatL(aOut, pair.Name());
    pair.Element().DoSerializeL(aOut);
  }
  aOut.WriteInt8L(0);
}

void CDocument::DoDeserializeL(RReadStream &aIn)
{
  TInt32 docLength = aIn.ReadInt32L();

  TStreamPos pos = aIn.Source()->TellL(MStreamBuf::ERead);
  while ( docLength - pos.Offset() > 1 )
  {
    HBufC* name = NULL;
    CElement* element = ::DeserializeElementLC(aIn, name);
    CleanupStack::PushL(name);
    AppendL(name, element);
    CleanupStack::Pop(2, element);
    pos = aIn.Source()->TellL(MStreamBuf::ERead);
  }

  ASSERT(aIn.ReadUint8L() == 0);
}

void CDocument::ParseL(const TDesC8& aData)
{
  RDesReadStream read(aData);
  CleanupClosePushL(read);
  ParseL(read);
  CleanupStack::PopAndDestroy(&read);
}

void CDocument::ParseL(RReadStream& aIn)
{
  DoDeserializeL(aIn);
}


}

